package org.wheel.plugins.toolkit.sql.segment;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.wheel.plugins.toolkit.sql.core.AbstractWrapper;
import org.wheel.plugins.toolkit.sql.enums.CompareType;
import org.wheel.plugins.toolkit.sql.enums.LogicalOp;
import org.wheel.plugins.toolkit.sql.helper.ColumnRef;
import org.wheel.plugins.toolkit.sql.helper.ParamBank;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * WHERE 条件节点 – 支持 Lambda/字符串双写法
 */
public final class WhereSegment extends AbstractWhereSegment {

    // 直接使用 LogFactory 创建日志对象，Hutool 会自动检测项目中的日志框架（优先级：Slf4j > Log4j > Logback > JDK Logging）
    private static final Log log = LogFactory.get();

    private final String rawExpr;   // 原始表达式（含 :name）
    private final AbstractWrapper<?, ?> wrapper;

    /**
     * 占位符块正则
     * 对于IN/NOT IN 语法，允许嵌套
     * 严格匹配 三种合法占位符形式的正则：
     * (:p0)
     * (:p0, :p1, :p2)
     * ((:p0, :p1, :p2), (:p3, :p4, :p5))
     * 不允许空元素、不允许缺失括号、不允许其他字符。
     */
    private static final Pattern PLACEHOLDER_BLOCK =
            Pattern.compile(
                    // 单层：(:p0) 或 (:p0 , :p1 , :p2) 允许任意空格
                    "(?:\\(\\s*:p\\d+\\s*(?:,\\s*:p\\d+\\s*)*\\))|" +
                            // 双层：((:p0 , :p1) , (:p2 , :p3)) 允许任意空格
                            "\\(\\(\\s*:p\\d+\\s*(?:,\\s*:p\\d+\\s*)*\\)(?:\\s*,\\s*\\(\\s*:p\\d+\\s*(?:,\\s*:p\\d+\\s*)*\\))*\\)",
                    Pattern.CASE_INSENSITIVE
            );

    private WhereSegment(LogicalOp logicalOp, String rawExpr, AbstractWrapper<?, ?> wrapper) {
        super(logicalOp, wrapper);
        this.rawExpr = rawExpr;
        this.wrapper = wrapper;
    }
    // ==========================================================
    //       万能工厂 – 一条走天下
    // ==========================================================
    public static WhereSegment of(CompareType type,
                                  ColumnRef ref,
                                  Object value,
                                  AbstractWrapper<?, ?> wrapper) {
        return of(LogicalOp.AND, type, ref.getSql(), value,  wrapper);
    }

    public static WhereSegment of(LogicalOp logicalOp,
                                  CompareType type,
                                  String column,
                                  Object value,
                                  AbstractWrapper<?, ?> wrapper) {
        ParamBank bank = wrapper.getContext().getParamBank();
        switch (type) {
            case IS_NULL:
            case IS_NOT_NULL:
                return new WhereSegment(logicalOp, StrUtil.format("{} {}", column, type.getOp()), wrapper);

            case BETWEEN:
            case NOT_BETWEEN:
                if (!(value instanceof Collection<?> && ((Collection<?>) value).size() == 2)) {
                    throw new IllegalArgumentException("BETWEEN 需要长度为 2 的 List");
                }
                String startKey = bank.nextParam((new ArrayList<>((Collection<?>) value)).get(0));
                String endKey = bank.nextParam((new ArrayList<>((Collection<?>) value)).get(1));
                /* 只读外部序号，不做 ++ */
                return new WhereSegment(logicalOp, StrUtil.format("{} {} :{} AND :{}",
                        column, type.getOp(), startKey, endKey), wrapper);

            case IN:
            case NOT_IN:
                if (!(value instanceof Collection<?> root)) {
                    throw new IllegalArgumentException("IN 需要 Collection");
                }
                // 1. 递归生成整棵树
                String placeholders = buildPlaceholdersRecursively(root, bank);
                if(!PLACEHOLDER_BLOCK.matcher(placeholders).matches()){
                    log.trace("IN/NOT IN 参数列表为空");
                    placeholders = "("+placeholders+")";
                }
                // 2. 外层加括号
                return WhereSegment.of(logicalOp,
                        StrUtil.format("{} {} {}", column, type.getOp(), placeholders),
                        wrapper);

            default: // EQ/LIKE/GT/LE...
                String key = bank.nextParam(value);
                return new WhereSegment(logicalOp, StrUtil.format("{} {} {}",
                        column, type.getOp(), ":"+key), wrapper);
        }
    }

    /**
     * 列 vs 列 或 任何已拼接好的最终表达式
     * 示例：of(LogicalOp.AND, "a.id = b.user_id")
     * @param logicalOp 用于和上一个where条件的连接符关系
     * @param rawExpr 任何已拼接好的原生SQL最终表达式
     * @return WhereSegment
     */
    public static WhereSegment of(LogicalOp logicalOp, String rawExpr,
                                  AbstractWrapper<?, ?> wrapper) {
        // 不再需要 :param 占位，直接 whole expression
        return new WhereSegment(logicalOp, rawExpr, wrapper);
    }

    /**
     * 判断对象值是否为集合，如果不是集合则返回 null，否则统一返回list
     * @param obj 对象值
     * @return  List集合
     */
    private static List<?> convertToCollection(Object obj) {
        if (obj instanceof Collection<?> col) {
            return col.stream().toList();
        }
        if (obj instanceof Map<?, ?>  map) {
            // Map 视为 entrySet
            return List.of(map.values());
        }
        if (ArrayUtil.isArray(obj)) {
            // 数组[] -> List
            return Arrays.stream(((Object[])obj)).toList();
        }
        // 单值返回 null 标识
        return null;
    }
    /**
     * 递归生成任意层级嵌套的占位符串
     * 返回已拼好的 SQL 片段，例如：
     *   单层 : (1,2,3)
     *   双层 : ((1,2),(3,4))
     *   三层 : ((1,2),(3,4),(5,6))
     */
    private static String buildPlaceholdersRecursively(Object value, ParamBank bank) {
        // 1. 集合/Map/数组：递归拆层
        List<?> coll = convertToCollection(value);
        if (coll != null && !coll.isEmpty() && coll.size()>1) {
            return coll.stream()
                    .map(item->buildPlaceholdersRecursively(item, bank))   // 递归
                    .collect(Collectors.joining(",", "(", ")"));
        }
        // 2. 单值：直接入库并占位
        return ":" + bank.nextParam(value);   // 返回 :key 或 $key 等
    }

    @Override
    public String getSql() {
        return rawExpr;
    }
}